using System;
using System.Collections.Generic;
using UnityEngine;

namespace CGF
{
    public class ComponentBase
    {
        private static List<ComponentBase> fixedUpdateList = new List<ComponentBase>();
        private static List<ComponentBase> updateList = new List<ComponentBase>();
        private static List<ComponentBase> lateUpdateList = new List<ComponentBase>();
        private static List<ComponentBase> appFocusList = new List<ComponentBase>();
        private static List<ComponentBase> appPauseList = new List<ComponentBase>();

        private Dictionary<Type, ComponentBase> components = new Dictionary<Type, ComponentBase>();
        private Dictionary<Type, Dictionary<int, ComponentBase>> childrenDic = new Dictionary<Type, Dictionary<int, ComponentBase>>();
        private Dictionary<Type, List<ComponentBase>> childrenList = new Dictionary<Type, List<ComponentBase>>();
        public ComponentBase Parent { get; private set; }
        public int Id { get; private set; }
        public bool IsDisposed { get; private set; }

        public T AddComponent<T>() where T : ComponentBase, IAwake, new()
        {
            Type type = typeof(T);
            if (components.ContainsKey(type))
            {
                LogError($"{GetType().Name} 里已存在 {type.Name}，不能用AddComponent重复添加，可以使用AddChild添加多个组件");
                return null;
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            components.Add(type, com);
            if (com is IAwake) (com as IAwake).Awake();
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            OnAddChildComponent(com);
            return com;
        }

        public T AddComponent<T, P>(P param) where T : ComponentBase, IAwake<P>, new()
        {
            Type type = typeof(T);
            if (components.ContainsKey(type))
            {
                LogError($"{GetType().Name} 里已存在 {type.Name}，不能用AddComponent重复添加，可以使用AddChild添加多个组件");
                return null;
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            components.Add(type, com);
            if (com is IAwake<P>) com.Awake(param);
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            OnAddChildComponent(com);
            return com;
        }

        public T AddComponent<T, P1, P2>(P1 param1, P2 param2) where T : ComponentBase, IAwake<P1, P2>, new()
        {
            Type type = typeof(T);
            if (components.ContainsKey(type))
            {
                LogError($"{GetType().Name} 里已存在 {type.Name}，不能用AddComponent重复添加，可以使用AddChild添加多个组件");
                return null;
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            components.Add(type, com);
            if (com is IAwake<P1, P2>) com.Awake(param1, param2);
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            OnAddChildComponent(com);
            return com;
        }

        public T AddComponent<T, P1, P2, P3>(P1 param1, P2 param2, P3 param3) where T : ComponentBase, IAwake<P1, P2, P3>, new()
        {
            Type type = typeof(T);
            if (components.ContainsKey(type))
            {
                LogError($"{GetType().Name} 里已存在 {type.Name}，不能用AddComponent重复添加，可以使用AddChild添加多个组件");
                return null;
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            components.Add(type, com);
            if (com is IAwake<P1, P2, P3>) com.Awake(param1, param2, param3);
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            OnAddChildComponent(com);
            return com;
        }

        public T AddComponent<T, P1, P2, P3, P4>(P1 param1, P2 param2, P3 param3, P4 param4) where T : ComponentBase, IAwake<P1, P2, P3, P4>, new()
        {
            Type type = typeof(T);
            if (components.ContainsKey(type))
            {
                LogError($"{GetType().Name} 里已存在 {type.Name}，不能用AddComponent重复添加，可以使用AddChild添加多个组件");
                return null;
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            components.Add(type, com);
            if (com is IAwake<P1, P2, P3, P4>) com.Awake(param1, param2, param3, param4);
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            OnAddChildComponent(com);
            return com;
        }

        public T GetComponent<T>() where T : ComponentBase
        {
            Type type = typeof(T);
            if (components.ContainsKey(type))
            {
                return components[type] as T;
            }
            return null;
        }

        public bool HasComponent<T>() where T : ComponentBase
        {
            Type type = typeof(T);
            return components.ContainsKey(type);
        }

        public void RemoveComponent<T>() where T : ComponentBase
        {
            Type type = typeof(T);
            if (components.ContainsKey(type))
            {
                ComponentBase com = components[type];
                com.Destroy();
            }
        }

        protected virtual void OnAddChildComponent(ComponentBase child) { }

        protected virtual void OnRemoveChildComponent(ComponentBase child)
        {
            if (UIManagerComponent.instance != null && child is UIComponentBase)
            {
                UIManagerComponent.instance.OnUIComponentRemove(child as UIComponentBase);
            }
        }

        public T AddChild<T>() where T : ComponentBase, IAwake, new()
        {
            Type type = typeof(T);
            List<ComponentBase> list = null;
            if (childrenList.ContainsKey(type))
            {
                list = childrenList[type];
            }
            else
            {
                list = new List<ComponentBase>();
                childrenList.Add(type, list);
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            list.Add(com);
            if (com is IAwake) (com as IAwake).Awake();
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            return com;
        }

        public T AddChild<T, P>(P param) where T : ComponentBase, IAwake<P>, new()
        {
            Type type = typeof(T);
            List<ComponentBase> list = null;
            if (childrenList.ContainsKey(type))
            {
                list = childrenList[type];
            }
            else
            {
                list = new List<ComponentBase>();
                childrenList.Add(type, list);
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            list.Add(com);
            if (com is IAwake<P>) (com as IAwake<P>).Awake(param);
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            return com;
        }

        public T AddChild<T, P1, P2>(P1 param1, P2 param2) where T : ComponentBase, IAwake<P1, P2>, new()
        {
            Type type = typeof(T);
            List<ComponentBase> list = null;
            if (childrenList.ContainsKey(type))
            {
                list = childrenList[type];
            }
            else
            {
                list = new List<ComponentBase>();
                childrenList.Add(type, list);
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            list.Add(com);
            if (com is IAwake<P1, P2>) (com as IAwake<P1, P2>).Awake(param1, param2);
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            return com;
        }

        public T AddChild<T, P1, P2, P3>(P1 param1, P2 param2, P3 param3) where T : ComponentBase, IAwake<P1, P2, P3>, new()
        {
            Type type = typeof(T);
            List<ComponentBase> list = null;
            if (childrenList.ContainsKey(type))
            {
                list = childrenList[type];
            }
            else
            {
                list = new List<ComponentBase>();
                childrenList.Add(type, list);
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            list.Add(com);
            if (com is IAwake<P1, P2, P3>) (com as IAwake<P1, P2, P3>).Awake(param1, param2, param3);
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            return com;
        }

        public T AddChild<T, P1, P2, P3, P4>(P1 param1, P2 param2, P3 param3, P4 param4) where T : ComponentBase, IAwake<P1, P2, P3, P4>, new()
        {
            Type type = typeof(T);
            List<ComponentBase> list = null;
            if (childrenList.ContainsKey(type))
            {
                list = childrenList[type];
            }
            else
            {
                list = new List<ComponentBase>();
                childrenList.Add(type, list);
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            list.Add(com);
            if (com is IAwake<P1, P2, P3, P4>) (com as IAwake<P1, P2, P3, P4>).Awake(param1, param2, param3, param4);
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            return com;
        }

        public T AddChildWithId<T>(int id) where T : ComponentBase, IAwake, new()
        {
            Type type = typeof(T);
            Dictionary<int, ComponentBase> list = null;
            if (childrenDic.ContainsKey(type))
            {
                list = childrenDic[type];
            }
            else
            {
                list = new Dictionary<int, ComponentBase>();
                childrenDic.Add(type, list);
            }
            if (list.ContainsKey(id))
            {
                LogError($"{GetType().Name} 里已存在 id 为 {id} 的 {type.Name}，不能重复添加");
                return null;
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            list.Add(id, com);
            com.Id = id;
            if (com is IAwake) (com as IAwake).Awake();
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            return com;
        }

        public T AddChildWithId<T, P>(int id, P param) where T : ComponentBase, IAwake<P>, new()
        {
            Type type = typeof(T);
            Dictionary<int, ComponentBase> list = null;
            if (childrenDic.ContainsKey(type))
            {
                list = childrenDic[type];
            }
            else
            {
                list = new Dictionary<int, ComponentBase>();
                childrenDic.Add(type, list);
            }
            if (list.ContainsKey(id))
            {
                LogError($"{GetType().Name} 里已存在 id 为 {id} 的 {type.Name}，不能重复添加");
                return null;
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            list.Add(id, com);
            com.Id = id;
            if (com is IAwake<P>) (com as IAwake<P>).Awake(param);
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            return com;
        }

        public T AddChildWithId<T, P1, P2>(int id, P1 param1, P2 param2) where T : ComponentBase, IAwake<P1, P2>, new()
        {
            Type type = typeof(T);
            Dictionary<int, ComponentBase> list = null;
            if (childrenDic.ContainsKey(type))
            {
                list = childrenDic[type];
            }
            else
            {
                list = new Dictionary<int, ComponentBase>();
                childrenDic.Add(type, list);
            }
            if (list.ContainsKey(id))
            {
                LogError($"{GetType().Name} 里已存在 id 为 {id} 的 {type.Name}，不能重复添加");
                return null;
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            list.Add(id, com);
            com.Id = id;
            if (com is IAwake<P1, P2>) (com as IAwake<P1, P2>).Awake(param1, param2);
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            return com;
        }

        public T AddChildWithId<T, P1, P2, P3>(int id, P1 param1, P2 param2, P3 param3) where T : ComponentBase, IAwake<P1, P2, P3>, new()
        {
            Type type = typeof(T);
            Dictionary<int, ComponentBase> list = null;
            if (childrenDic.ContainsKey(type))
            {
                list = childrenDic[type];
            }
            else
            {
                list = new Dictionary<int, ComponentBase>();
                childrenDic.Add(type, list);
            }
            if (list.ContainsKey(id))
            {
                LogError($"{GetType().Name} 里已存在 id 为 {id} 的 {type.Name}，不能重复添加");
                return null;
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            list.Add(id, com);
            com.Id = id;
            if (com is IAwake<P1, P2, P3>) (com as IAwake<P1, P2, P3>).Awake(param1, param2, param3);
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            return com;
        }

        public T AddChildWithId<T, P1, P2, P3, P4>(int id, P1 param1, P2 param2, P3 param3, P4 param4) where T : ComponentBase, IAwake<P1, P2, P3, P4>, new()
        {
            Type type = typeof(T);
            Dictionary<int, ComponentBase> list = null;
            if (childrenDic.ContainsKey(type))
            {
                list = childrenDic[type];
            }
            else
            {
                list = new Dictionary<int, ComponentBase>();
                childrenDic.Add(type, list);
            }
            if (list.ContainsKey(id))
            {
                LogError($"{GetType().Name} 里已存在 id 为 {id} 的 {type.Name}，不能重复添加");
                return null;
            }
            T com = Activator.CreateInstance(type) as T;
            com.Parent = this;
            list.Add(id, com);
            com.Id = id;
            if (com is IAwake<P1, P2, P3, P4>) (com as IAwake<P1, P2, P3, P4>).Awake(param1, param2, param3, param4);
            if (com is IFixedUpdate) fixedUpdateList.Add(com);
            if (com is IUpdate) updateList.Add(com);
            if (com is ILateUpdate) lateUpdateList.Add(com);
            if (com is IAppFocus) appFocusList.Add(com);
            if (com is IAppPause) appPauseList.Add(com);
            return com;
        }

        public List<ComponentBase> GetChildren<T>() where T : ComponentBase
        {
            Type type = typeof(T);
            if (childrenList.ContainsKey(type))
            {
                return childrenList[type];
            }
            return null;
        }

        public T GetChildById<T>(int id) where T : ComponentBase
        {
            Type type = typeof(T);
            if (childrenDic.ContainsKey(type))
            {
                Dictionary<int, ComponentBase> list = childrenDic[type];
                if (list.ContainsKey(id))
                {
                    return list[id] as T;
                }
            }
            return null;
        }

        public void RemoveChild<T>(int id) where T : ComponentBase
        {
            Type type = typeof(T);
            if (childrenDic.ContainsKey(type))
            {
                Dictionary<int, ComponentBase> list = childrenDic[type];
                if (list.ContainsKey(id))
                {
                    ComponentBase com = list[id];
                    com.Destroy();
                }
            }
        }

        public T GetParent<T>() where T : ComponentBase
        {
            return Parent as T;
        }

        public void Destroy()
        {
            //触发自己的OnDestroy()方法
            if (this is IDestroy) (this as IDestroy).OnDestroy();

            //销毁所有孩子
            List<ComponentBase> toDisposeChildren = new List<ComponentBase>();
            foreach (var children in childrenDic.Values)
            {
                foreach (var child in children.Values)
                {
                    toDisposeChildren.Add(child);
                }
            }
            foreach (var children in childrenList.Values)
            {
                foreach (var child in children)
                {
                    toDisposeChildren.Add(child);
                }
            }
            foreach (var child in components.Values)
            {
                toDisposeChildren.Add(child);
            }
            for (int i = 0; i < toDisposeChildren.Count; i++)
            {
                toDisposeChildren[i].Destroy();
            }

            //把自己从父级移除
            if (fixedUpdateList.Contains(this)) fixedUpdateList.Remove(this);
            if (updateList.Contains(this)) updateList.Remove(this);
            if (lateUpdateList.Contains(this)) lateUpdateList.Remove(this);
            if (appFocusList.Contains(this)) appFocusList.Remove(this);
            if (appPauseList.Contains(this)) appPauseList.Remove(this);
            if (Parent != null)
            {
                Parent.OnRemoveChildComponent(this);
                Type type = GetType();
                if (Parent.components.ContainsKey(type))
                {
                    Parent.components.Remove(type);
                }
                if (Parent.childrenDic.ContainsKey(type))
                {
                    Dictionary<int, ComponentBase> dic = Parent.childrenDic[type];
                    if (dic.ContainsKey(Id))
                    {
                        dic.Remove(Id);
                        if (dic.Count == 0)
                        {
                            Parent.childrenDic.Remove(type);
                        }
                    }
                }
                if (Parent.childrenList.ContainsKey(type))
                {
                    List<ComponentBase> dic = Parent.childrenList[type];
                    for (int i = 0; i < dic.Count; i++)
                    {
                        if (dic[i] == this)
                        {
                            dic.RemoveAt(i);
                            if (dic.Count == 0)
                            {
                                Parent.childrenList.Remove(type);
                            }
                            break;
                        }
                    }
                }
            }
            Parent = null;
            IsDisposed = true;
        }

        //系统保留，不要调用
        public static void _FixedUpdate()
        {
            for (int i = 0; i < fixedUpdateList.Count; i++)
            {
                ComponentBase com = fixedUpdateList[i];
                (com as IFixedUpdate).FixedUpdate();
            }
        }

        //系统保留，不要调用
        public static void _Update()
        {
            for (int i = 0; i < updateList.Count; i++)
            {
                ComponentBase com = updateList[i];
                (com as IUpdate).Update();
            }
        }

        //系统保留，不要调用
        public static void _LateUpdate()
        {
            for (int i = 0; i < lateUpdateList.Count; i++)
            {
                ComponentBase com = lateUpdateList[i];
                (com as ILateUpdate).LateUpdate();
            }
        }

        //系统保留，不要调用
        public static void _AppFocus(bool focus)
        {
            for (int i = 0; i < appFocusList.Count; i++)
            {
                ComponentBase com = appFocusList[i];
                (com as IAppFocus).OnAppFocus(focus);
            }
        }

        //系统保留，不要调用
        public static void _AppPause(bool pause)
        {
            for (int i = 0; i < appPauseList.Count; i++)
            {
                ComponentBase com = appPauseList[i];
                (com as IAppPause).OnAppPause(pause);
            }
        }

        protected void Log(object content)
        {
            Debug.Log($"[{GetType().Name}]{content}");
        }

        protected void LogWarning(object content)
        {
            Debug.LogWarning($"[{GetType().Name}]{content}");
        }

        protected void LogError(object content)
        {
            Debug.LogError($"[{GetType().Name}]{content}");
        }
    }
}
